package dslProgramGen;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DslClassesGen {
    HashSet<String> classSet = new HashSet<String>();
    HashSet<String> interfaceSet = new HashSet<String>();
    String filePath;
    String outPath;
    BufferedReader reader;

    public static void main(String[] args) {
        String filePath = "src/test/resources/dslProgramGenForComplexMop/rawTraces/class_12.txt";
        String outPath = "src/test/resources/dslProgramGenForComplexMop/rawTraces/";
        DslClassesGen parser = new DslClassesGen(filePath, outPath);
        parser.parse();
    }

    public DslClassesGen(String filePath, String outPath) {
        this.filePath = filePath;
        this.outPath = outPath;
    }

    public void parse() {
        collectClassInterface();
        outputClass();
    }

    public void collectClassInterface() {
        try {
            reader = new BufferedReader(new FileReader(filePath));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("class ")) {
                    Pattern pattern = Pattern.compile("class\\s+([\\w\\$]+)");
                    Matcher matcher = pattern.matcher(line);
                    if (matcher.find()) {
                        String className = matcher.group(1);
                        classSet.add(className);
                    }
                } else if (line.startsWith("interface ")) {
                    Pattern pattern = Pattern.compile("interface\\s+([\\w\\$]+)");
                    Matcher matcher = pattern.matcher(line);
                    if (matcher.find()) {
                        String interfaceName = matcher.group(1);
                        interfaceSet.add(interfaceName);
                    }
                }
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void outputClass() {
        try {
            reader = new BufferedReader(new FileReader(filePath));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("class ") || line.startsWith("interface ")) {
                    parseClass(line);
                }
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void parseClass(String line) throws IOException {
        Pattern pattern = Pattern.compile("(class|interface)\\s+([\\w\\$]+)");
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            String classType = matcher.group(1);
            String className = matcher.group(2);
            StringBuilder classContent = new StringBuilder(classType + " " + className + " {\n");
            String outFile = outPath.concat("MainClasses").concat(".txt");
            BufferedWriter writer = new BufferedWriter(new FileWriter(outFile, true));
            String nextLine;
            HashSet<String> fieldSet = new HashSet<String>();
            while ((nextLine = reader.readLine()) != null && !nextLine.startsWith("}")) {
                if (nextLine.trim().isEmpty()) {
                    continue;
                }
                nextLine = nextLine.trim();
                String[] words = nextLine.split(" ");
                int wordLen = words.length;
                words[wordLen - 2] = convertTypeSignature(words[wordLen - 2]);
                if (fieldSet.contains(words[wordLen - 1])) {
                    continue;
                }
                fieldSet.add(words[wordLen - 1]);
                classContent.append("\t").append("").append(String.join(" ", words)).append("\n");
            }

            classContent.append("}\n");
            writer.write(classContent.toString());
            writer.flush();
            writer.close();
        }
    }

    private String convertTypeSignature(String type) {
        switch (type) {
            case "Z":
                return "boolean";
            case "B":
                return "byte";
            case "C":
                return "char";
            case "S":
                return "short";
            case "I":
                return "int";
            case "J":
                return "long";
            case "F":
                return "float";
            case "D":
                return "double";
            default:
                if (type.startsWith("L") && type.endsWith(";")) {
                    return convertTypeSignature(type.substring(1, type.length() - 1));
                } else if (type.startsWith("[")) {
                    String elementType = convertTypeSignature(type.substring(1));
                    return elementType + "[]";
                } else {
                    // replace interface with "java_lang_Object"
                    if (interfaceSet.contains(type)) {
                        return "java_lang_Object";
                    } else if (classSet.contains(type)) {
                    } else {
                        // for uninitialized type, use java_lang_Object to skip it.
                        return "java_lang_Object";
                    }
                    return type;
                }
        }
    }

}
